package net.borlis.sample.service.db.em;

import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author alex@borlis.net on 3/21/2014.
 */
@Interceptor
@Transaction
public class TransactionInterceptor {

    @Inject
    private Logger logger;

    @Inject
    private EntityManager em;

    @AroundInvoke  //todo:: process join transaction
    public Object transactionProceed(InvocationContext ctx) throws Exception {//NOPMD
        // there is a conflict between SONAR/CDI
        try {
            logger.log(Level.FINE, "The transaction processing has been started.");
            logger.log(Level.ALL, "The status: " + em.isJoinedToTransaction());
            em.getTransaction().begin();
            // -=-=-=-=-=-
            logger.log(Level.ALL, "The class name: " + ctx.getMethod().getDeclaringClass().getName());
            logger.log(Level.ALL, "The method name: " + ctx.getMethod().getName());
            logger.log(Level.ALL, "The content data: " + ctx.getContextData().toString());
            Object result = ctx.proceed();
            // -=-=-=-=-=-
            em.getTransaction().commit();
            // -=-=-=-=-=-
            logger.log(Level.FINE, "The transaction has been finished.");
            return result;
        } catch (Exception error) {
            try {
                em.getTransaction().rollback();
                logger.log(Level.WARNING, "The transaction has been rolled back.", error);
            } catch (Exception et) {
                logger.log(Level.SEVERE, "Rollback of transaction failed -> ", et);
            }
            //todo:: tempo solution - process by normal way!!!
            throw new IllegalStateException(error.getMessage(), error);
        }
    }

    @PreDestroy
    public void destroy(InvocationContext ctx) {
        logger.log(Level.ALL, "The content data: " + ctx.getContextData().toString());
        if (em.isOpen()) {
            em.close();
        }
    }
}
